<!doctype html>
<html lang="zh" class="h-100">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="assets/css/bootstrap.min.css">
    <link rel="stylesheet" href="assets/css/style.css">

    <title>Server 服务器组件.md</title>
  </head>
  <body class="h-100">
  <div class="container-fluid h-100 p-2">
  	<p>server组件代表了beyod运行实例，它是整个网络框架的基础。server组件中又包含了一系列的Listeners组件配置。</p><p>可以从beyoioServer类继承，实现自定义server组件类，只要在在配置文件中指定class即可。  </p><p>在任何位置，可以通过以下代码引用server组件对象：</p><pre><code>\Yii::$app-&gt;server;</code></pre><p>server组件提供一个重要的方法：</p><pre><code>public function onWorkerStart($workerId, $GPID){
    
}</code></pre><p>它运行在工作进程空间，当所有Listenners已经监听并开始准备接受客户端连接时，此方法被运行，你可以扩展自己的逻辑，实现个性化的功能(比如初始化操作，连接到订阅器，基于进程角色的任务调度等)。</p><p><strong>workerId</strong>  <br>workderid是非常重要的概念，它是指工作进程的顺序号（并不是pid），从1开始，当一个进程崩溃后，被主进程重新生成替补后，它的workerId是不变的。我们可以根据此值，实现进程功能区分，使不同的进程处理不同的任务。  <br>可以在任何位置使用以下方式取得当前进程的Workerid:</p><pre><code>\Yii::$app-&gt;server-&gt;getWorkerId();</code></pre><p><strong>GPID</strong>  <br>全局进程唯一id(Global process unique identification), 在集群环境中，存在多台服务器的情况下，客户端可能连接到任何一台服务器的某个工作进程，</p><p>beyod诞生之初就考虑到分布式环境集群化部署，引入了GPID概念，它用来在集群环境中为每个工作进程分配全局唯一的id。</p><p>GPDI本质上是由 server_id和workerID组成，算法为：</p><pre><code>$GPID = ($server_id &lt;&lt; 16)+$workderId;</code></pre><p>所以，集群环境要保证每台服务器的server_id不能一样。</p><p>显然，从理论上来说，单个beyod实例最多只能有65535个工作进程。  </p><p>可以在任何位置得到当前进程的GPID:</p><pre><code>\Yii::$app-&gt;server-&gt;GPID;

//或
\Yii::$app-&gt;server-&gt;getGPID();</code></pre><p>当客户端连接到不同的工作进程中时（或同一台机器的不同工作进程），它们属于不同的进程空间，无法直接通信。如果要互相通信，就需要一个共享通道。</p><p>典型的，如果我们要开发一个物联网应用，用户需要通过手机/网页向设备下发指令， 但架构是以多台服务器集群方式运行，这时就需要有GPID的帮助，以快速定位设备所在具体进程。原理如下：</p><ol><li>工作进程启动后，即向订阅器（dispatcher/redis等）订阅频道，频道名称即为自己的GPID。</li><li>设备连接后，我们将device_id与GPID的映射结构保存到共享存储系统（如dispatcher/redis/memcache/database）中。</li><li>当需要向终端设置发送数据时，我们在第2步的共享存储系统中根据device_id找到GPID。</li><li>我们向订阅器(dispatcher/redis等)发布消息,频道号即为第3步找到的GPID，那么订阅了此频道的工作进程就会收到此消息，从而实现集群通信。</li></ol><p>实现此种架构，最直接的有两种方式：</p><ol><li>使用beyod自带的dispatcher实现</li><li>使用redis/或其它订阅器实现</li></ol><p>当然，使用其它类似的方式也要完全可以的，但基本原理却是相通的。</p><p>当然，如果你的终端设备较少，完全可以使用单机单进支持上万个连接还是没有问题的。</p><p>可以使用keeppalived/heartbeat等工具，实现主-备高可用自动切换。</p><p>当然，使用单进程的一个弊端是，多核CPU资源不能充分使用。要根据负载量设计合理方案，避免过度设计和简单问题复杂化。</p>  </div>
  <script src="assets/js/jquery.min.js"></script>
  <script src="assets/js/popper.min.js"></script>
  <script src="assets/js/bootstrap.min.js"></script>

<script>
$(function(){
  var url = self.location;
  parent.$('a').removeClass('font-weight-bold');
  parent.$('a[href="13.html"]').addClass('font-weight-bold');
});
</script>  
  
  </body>
</html>